package com.ecoolex.union.pay.retailer.ws;

import com.ecoolex.framework.common.pojo.Page;
import com.ecoolex.framework.common.pojo.Pagination;
import com.ecoolex.union.pay.retailer.core.manager.UnionPayPopularMerchantManager;
import com.ecoolex.union.pay.retailer.core.manager.UnionPayPopularMerchantProductManager;
import com.ecoolex.union.pay.retailer.core.util.unionpay.LogUtil;
import com.ecoolex.union.pay.retailer.entity.UnionPayPopularMerchant;
import com.ecoolex.union.pay.retailer.entity.UnionPayPopularMerchantProduct;
import com.ecoolex.union.pay.retailer.pojo.UnionPayPopularMerchantDTO;
import com.ecoolex.union.pay.retailer.pojo.UnionPayPopularMerchantWithProductDTO;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.dubbo.config.annotation.Reference;
import org.apache.dubbo.config.annotation.Service;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.Cursor;
import org.springframework.data.redis.core.ScanOptions;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;

import javax.annotation.PostConstruct;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.function.Consumer;

@Service
public class UnionPayPopularMerchantServiceImpl implements UnionPayPopularMerchantService{

    @Autowired
    UnionPayPopularMerchantManager unionPayPopularMerchantManager;

    @Autowired
    UnionPayPopularMerchantProductManager unionPayPopularMerchantProductManager;

    @Autowired
    StringRedisTemplate redisTemplate;

    @Autowired
	Jackson2ObjectMapperBuilder jacksonObjectMapperBuilder;

	private ObjectMapper objectMapper;

	@PostConstruct
	public void init() {
		objectMapper = jacksonObjectMapperBuilder
				.dateFormat(new SimpleDateFormat("yyyyMMddHHmmss", new Locale("zh", "cn"))).build();
	}

    @Reference
    UnionPayPopularMerchantProductService unionPayPopularMerchantProductService;

    @Override
    public List<UnionPayPopularMerchantDTO> getPopularMerchantList() {
        String key = UnionPayPopularMerchantService.MERCHANT ;
        Long size = redisTemplate.opsForValue().size(key);
        List<UnionPayPopularMerchantDTO> dtos = new ArrayList(size.intValue());
		try {
			if (size > 0) {
				String json = redisTemplate.opsForValue().get(key);
				List<UnionPayPopularMerchantDTO> temp = objectMapper.readValue(json, dtos.getClass());
				dtos.addAll(temp);
			}
			else {
				dtos = unionPayPopularMerchantManager.getPopularMerchantList();
				String json = objectMapper.writeValueAsString(dtos);
				redisTemplate.opsForValue().set(key, json);
			}

		}
		catch (Exception e) {
			LogUtil.writeErrorLog("", e);
        }
        return dtos;
    }

    @Override
    public UnionPayPopularMerchant addMerchant(UnionPayPopularMerchant record, String userName) {
        return unionPayPopularMerchantManager.addMerchant(record,userName);
    }

    @Override
    public UnionPayPopularMerchant get(Integer id) {
        return unionPayPopularMerchantManager.get(id);
    }

    @Override
	public UnionPayPopularMerchant getByMerchantId(String merchantId) {
		// TODO Auto-generated method stub
		return null;
	}

    @Override
    public UnionPayPopularMerchant editMerchant(UnionPayPopularMerchant old,String oldMerchantId, String userName) {
        return unionPayPopularMerchantManager.editMerchant(old,oldMerchantId,userName);
    }

    @Override
    public Pagination<UnionPayPopularMerchantWithProductDTO> queryMerchant(String keyword, Page page) {
        Pagination<UnionPayPopularMerchant> unionPayPopularMerchantPagination = unionPayPopularMerchantManager.queryMerchant(keyword, page);
        Pagination<UnionPayPopularMerchantWithProductDTO> unionPayPopularMerchantWithProductDTOPagination = unionPayPopularMerchantPagination.map(merchant -> {
            UnionPayPopularMerchantWithProductDTO dto = new UnionPayPopularMerchantWithProductDTO();
            BeanUtils.copyProperties(merchant,dto);
            List<UnionPayPopularMerchantProduct> unionPayPopularMerchantProducts = unionPayPopularMerchantProductManager.getPopularProduct(merchant.getMerchantId());
            dto.setMerchantProducts(unionPayPopularMerchantProducts);
            return dto;
        });
        return unionPayPopularMerchantWithProductDTOPagination;
    }

    @Override
    public void delete(UnionPayPopularMerchant merchant, String userName) {
        unionPayPopularMerchantManager.delete(merchant, userName);
    }

    public void syncToCache() {
        String merchantKey = UnionPayPopularMerchantService.MERCHANT ;
        redisTemplate.delete(merchantKey);
        String productKey = UnionPayPopularMerchantService.PRODUCT + "*";
        redisTemplate.keys(productKey).forEach(redisTemplate::delete);
        List<UnionPayPopularMerchantDTO> popularMerchantDTOS = getPopularMerchantList();
        popularMerchantDTOS.stream().map(UnionPayPopularMerchantDTO::getMerchantId).forEach(unionPayPopularMerchantProductService::getPopularProducts);

    }

    /**
     * scan 实现
     * @param pattern	表达式
     * @param consumer	对迭代到的key进行操作
     */
    public void scan(String pattern, Consumer<byte[]> consumer) {
        this.redisTemplate.execute((RedisConnection connection) -> {
            try (Cursor<byte[]> cursor = connection.scan(ScanOptions.scanOptions().count(Long.MAX_VALUE).match(pattern).build())) {
                cursor.forEachRemaining(consumer);
                return null;
            } catch (IOException e) {
                LogUtil.writeErrorLog(e.getMessage(),e);
                throw new RuntimeException(e);
            }
        });
    }

    /**
     * 获取符合条件的key
     * @param pattern	表达式
     * @return
     */
    public List<String> keys(String pattern) {
        List<String> keys = new ArrayList<>();
        this.scan(pattern, item -> {
            //符合条件的key
            String key = new String(item, StandardCharsets.UTF_8);
            keys.add(key);
        });
        return keys;
    }

}
